﻿// Microsoft Public License (Ms-PL)
// nRoute v5 (http://nroute.codeplex.com)
// Modifié par So@t

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using CPN.PJN.Silverlight.UI.Interactions.Interactivity;

namespace CPN.PJN.Silverlight.UI.Interactions.Actions
{
    public class ExecuteCommandAction : TriggerAction<DependencyObject>
    {
        const double INTERACTIVITY_ENABLED = 1d;
        const double INTERACTIVITY_DISABLED = 0.5d;

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(ExecuteCommandAction),
            new PropertyMetadata(null, ExecuteCommandAction.HandleCommandChanged));

        public static readonly DependencyProperty ParameterProperty =
            DependencyProperty.Register("Parameter", typeof(object), typeof(ExecuteCommandAction),
            new PropertyMetadata(null, new PropertyChangedCallback(OnParameterChanged)));


        #region UseTriggerParameter (DependencyProperty)

        /// <summary>
        /// A description of the property.
        /// </summary>
        public bool UseTriggerParameter
        {
            get { return (bool)GetValue(UseTriggerParameterProperty); }
            set { SetValue(UseTriggerParameterProperty, value); }
        }
        public static readonly DependencyProperty UseTriggerParameterProperty =
            DependencyProperty.Register("UseTriggerParameter", typeof(bool), typeof(ExecuteCommandAction),
              new PropertyMetadata(false));

        #endregion


        bool _manageEnableState;

        #region Properties

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        //[TypeConverter(typeof(ConvertFromStringConverter))]
        public object Parameter
        {
            get { return GetValue(ParameterProperty); }
            set { SetValue(ParameterProperty, value); }
        }

        public bool ManageEnableState
        {
            get { return _manageEnableState; }
            set { _manageEnableState = value; }
        }

        #endregion

        #region Trigger Related

        protected override void OnAttached()
        {
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            DisposeEnableState();
        }

        protected override void Invoke(object parameter)
        {
            object commandParameter = null;

            if (UseTriggerParameter)
            {
                commandParameter = parameter;
            }
            else
            {
                commandParameter = this.Parameter;
            }

            if (Command != null && Command.CanExecute(commandParameter))
            {
                Command.Execute(commandParameter);
            }
        }

        #endregion

        #region Handlers

        private static void HandleCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ExecuteCommandAction)d).SetupEnableState(e.NewValue as ICommand, e.OldValue as ICommand);
        }

        private static void OnParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ExecuteCommandAction)d).UpdateEnabledState();
        }

        void Command_CanExecuteChanged(object sender, EventArgs e)
        {
            this.UpdateEnabledState();
        }

        #endregion

        #region Helpers

        void SetupEnableState(ICommand newCommand, ICommand oldCommand)
        {
            // basic checks
            if (!ManageEnableState || AssociatedObject == null) return;

            // we detach or attach
            if (oldCommand != null)
                oldCommand.CanExecuteChanged -= new EventHandler(Command_CanExecuteChanged);
            if (newCommand != null)
                newCommand.CanExecuteChanged += new EventHandler(Command_CanExecuteChanged);

            // and update
            UpdateEnabledState();
        }

        void UpdateEnabledState()
        {
            // basic checks
            if (!ManageEnableState || AssociatedObject == null || Command == null) return;

            // we get if it is enabled or not
            var _canExecute = Command.CanExecute(this.Parameter);

            // we check if it is a control            
            if (typeof(Control).IsAssignableFrom(AssociatedObject.GetType()))
            {
                // we check if 
                var _control = AssociatedObject as Control;
                _control.IsEnabled = _canExecute;
            }
            else
            {
                FrameworkElement el = AssociatedObject as FrameworkElement;
                if (el != null)
                {
                    el.IsHitTestVisible = _canExecute;
                    el.Opacity = _canExecute ? INTERACTIVITY_ENABLED : INTERACTIVITY_DISABLED;
                }
            }
        }

        void DisposeEnableState()
        {
            if (!ManageEnableState || AssociatedObject == null || Command == null) return;

            if (AssociatedObject as Control != null)
                Command.CanExecuteChanged -= new EventHandler(Command_CanExecuteChanged);
        }

        #endregion

    }
}
